#include "Avalon/IOTests/DelimitedReaderTester.hpp"
#include "Avalon/IO/Buffer.hpp"
#include "Avalon/IO/BufferReader.hpp"
#include "Avalon/IO/DelimitedReader.hpp"
#include "Avalon/IO/EndOfFileException.hpp"

using namespace Avalon;
using namespace Avalon::IO;
using namespace Avalon::IO::Tests;
using namespace Avalon::Threading;
using namespace boost;
using namespace std;

void DelimitedReaderTester::TestEmpty() {
  BufferReader bufferReader(BufferFromString(""));
  DelimitedReader delimitedReader(bufferReader, '^');
  Async<int> readResult;
  Buffer buffer;
  delimitedReader.Read(&buffer, Store(readResult));
  CPPUNIT_ASSERT_THROW(readResult.Get(), EndOfFileException);
}

void DelimitedReaderTester::TestWithoutDelimiter() {
  string message = "hello world";
  BufferReader bufferReader(BufferFromString(message));
  DelimitedReader delimitedReader(bufferReader, '^');
  Async<int> readResult;
  Buffer buffer;
  delimitedReader.Read(&buffer, Store(readResult));
  CPPUNIT_ASSERT_THROW(readResult.Get(), EndOfFileException);
}

void DelimitedReaderTester::TestSingleDelimiter() {
  string message = "hello world^";
  BufferReader bufferReader(BufferFromString(message));
  DelimitedReader delimitedReader(bufferReader, '^');
  Async<int> readResult;
  Buffer data;
  delimitedReader.Read(&data, Store(readResult));
  CPPUNIT_ASSERT(readResult.Get() == message.size() - 1);
  CPPUNIT_ASSERT(data.GetSize() == message.size() - 1);
  CPPUNIT_ASSERT(strncmp(data.GetData(), message.c_str(),
    message.size() - 1) == 0);
  readResult.Reset();
  delimitedReader.Read(&data, Store(readResult));
  CPPUNIT_ASSERT_THROW(readResult.Get(), EndOfFileException);
}

void DelimitedReaderTester::TestTwoDelimiters() {
  string message = "hello world^goodbye sky^";
  BufferReader bufferReader(BufferFromString(message));
  DelimitedReader delimitedReader(bufferReader, '^');
  Async<int> readResult;
  Buffer data;
  delimitedReader.Read(&data, Store(readResult));
  CPPUNIT_ASSERT(readResult.Get() == 11);
  CPPUNIT_ASSERT(data.GetSize() == 11);
  CPPUNIT_ASSERT(strncmp(data.GetData(), message.c_str(), 11) == 0);
  readResult.Reset();
  data.Reset();
  delimitedReader.Read(&data, Store(readResult));
  CPPUNIT_ASSERT(readResult.Get() == 11);
  CPPUNIT_ASSERT(data.GetSize() == 11);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "goodbye sky", 11) == 0);
  readResult.Reset();
  delimitedReader.Read(&data, Store(readResult));
  CPPUNIT_ASSERT_THROW(readResult.Get(), EndOfFileException);
}

void DelimitedReaderTester::TestWithAndWithoutDelimiters() {
  string message = "hello world^goodbye sky";
  BufferReader bufferReader(BufferFromString(message));
  DelimitedReader delimitedReader(bufferReader, '^');
  Async<int> readResult;
  Buffer data;
  delimitedReader.Read(&data, Store(readResult));
  CPPUNIT_ASSERT(readResult.Get() == 11);
  CPPUNIT_ASSERT(data.GetSize() == 11);
  CPPUNIT_ASSERT(strncmp(data.GetData(), message.c_str(), 11) == 0);
  readResult.Reset();
  data.Reset();
  delimitedReader.Read(&data, Store(readResult));
  CPPUNIT_ASSERT_THROW(readResult.Get(), EndOfFileException);
}

void DelimitedReaderTester::TestManyDelimiters() {
  const int LETTER_COUNT = 7;
  string message = "a^b^c^d^e^f^g^";
  BufferReader bufferReader(BufferFromString(message));
  DelimitedReader delimitedReader(bufferReader, '^');
  char nextLetter = message[0];
  for(int i = 0; i < LETTER_COUNT; ++i) {
    Async<int> readResult;
    Buffer data;
    delimitedReader.Read(&data, Store(readResult));
    CPPUNIT_ASSERT(readResult.Get() == 1);
    CPPUNIT_ASSERT(data.GetSize() == 1);
    CPPUNIT_ASSERT(strncmp(data.GetData(), &nextLetter, 1) == 0);
    if(i == LETTER_COUNT - 1) {
      readResult.Reset();
      delimitedReader.Read(&data, Store(readResult));
      CPPUNIT_ASSERT_THROW(readResult.Get(), EndOfFileException);
    }
    ++nextLetter;
  }
}

void DelimitedReaderTester::TestReadSome() {
  string message = "hello^world^";
  BufferReader bufferReader(BufferFromString(message));
  DelimitedReader delimitedReader(bufferReader, '^');
  Async<int> readResult;
  Buffer data;
  delimitedReader.Read(&data, 3, Store(readResult));
  CPPUNIT_ASSERT(readResult.Get() == 3);
  CPPUNIT_ASSERT(data.GetSize() == 3);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "hel", 3) == 0);
  readResult.Reset();
  data.Reset();
  delimitedReader.Read(&data, 100, Store(readResult));
  CPPUNIT_ASSERT(readResult.Get() == 2);
  CPPUNIT_ASSERT(data.GetSize() == 2);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "lo", 2) == 0);
  readResult.Reset();
  data.Reset();
  delimitedReader.Read(&data, 3, Store(readResult));
  CPPUNIT_ASSERT(readResult.Get() == 3);
  CPPUNIT_ASSERT(data.GetSize() == 3);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "wor", 3) == 0);
  readResult.Reset();
  data.Reset();
  delimitedReader.Read(&data, 100, Store(readResult));
  CPPUNIT_ASSERT(readResult.Get() == 2);
  CPPUNIT_ASSERT(data.GetSize() == 2);
  CPPUNIT_ASSERT(strncmp(data.GetData(), "ld", 2) == 0);
  readResult.Reset();
  delimitedReader.Read(&data, Store(readResult));
  CPPUNIT_ASSERT_THROW(readResult.Get(), EndOfFileException);
}
